/* Copyright   1991 Gustavus Adolphus College.  All rights reserved.
 *
 * Schematik was developed by Gustavus Adolphus College (GAC) with
 * support from NeXT Computer, Inc.  Permission to copy this software,
 * to redistribute it, and to use it for any purpose is granted,
 * subject to the following restrictions and understandings.
 *
 * 1. Any copy made of this software must include this copyright
 * notice in full.
 *
 * 2. Users of this software agree to make their best efforts (a) to
 * return to the GAC Mathematics and Computer Science Department any
 * improvements or extensions that they make, so that these may be
 * included in future releases; and (b) to inform GAC of noteworthy
 * uses of this software.
 *
 * 3. All materials developed as a consequence of the use of this
 * software shall duly acknowledge such use, in accordance with the
 * usual standards of acknowledging credit in academic research.
 *
 * 4. GAC makes no express or implied warranty or representation of
 * any kind with respect to this software, including any warranty
 * that the operation of this software will be error-free.  ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
 * PURPOSE IS HEREBY DISCLAIMED.  GAC is under no obligation to
 * provide any services, by way of maintenance, update, or otherwise.
 *
 * 5. In conjunction with products arising from the use of this
 * material, there shall be no use of the name of Gustavus Adolphus
 * College nor of any adaptation thereof in any advertising,
 * promotional, or sales literature without prior written consent
 * from GAC in each case.
 */

#import "GraphicsView.h"
#import "../defines.h"
#import Main_h
#import SchemeProtocol_h
#import PrefAgent_h
#import <appkit/NXCachedImageRep.h>
#import <appkit/NXImage.h>
#import <appkit/ScrollView.h>
#import <appkit/Window.h>
#import <appkit/nextstd.h>
#import <appkit/publicWraps.h>
#import <dpsclient/wraps.h>
#import <objc/Storage.h>
#import <defaults.h>
#import <mach.h>
#import <string.h>

static void flushTEHandler(DPSTimedEntry, double, id);

#define GRAPHICSZONENAME	"Graphics"
#define MINIWINDOWICON		"GraphicsWin.tiff"
#define TEMPSTRINGLENGTH	1040
#define WINDOWOFFSET		20
#define WINDOWTOPBOUND		830
#define WINDOWROLLBOUND		800
#define WINDOWRIGHTBOUND	1050
#define AUTOFLUSHMODE		1
#define NONFLUSHMODE		0
#define MINDOCVIEWSIZE		{120.0,60.0}

static unsigned windowNumber=0;
static NXSize minWindowSize;

@implementation GraphicsView

+ initialize
{
    NXSize minDocSize=MINDOCVIEWSIZE,size1;
    NXRect tempFrame,tempRect;
    [ScrollView getFrameSize:&size1 forContentSize:&minDocSize horizScroller:YES vertScroller:YES borderType:NX_NOBORDER];
    NXSetRect(&tempRect,0.0,0.0,size1.width,size1.height);
    [Window getFrameRect:&tempFrame forContentRect:&tempRect style:NX_RESIZEBARSTYLE];
    minWindowSize.width=tempFrame.size.width;
    minWindowSize.height=tempFrame.size.height;
    return self;
}

- initFrame:(NXRect *)frameRect window:(unsigned)winNum
{
    NXSize size1,size2,size3,size4=MINDOCVIEWSIZE,size5;
    NXRect contentRect;
    id theWindow,scrollView;
    char buffer[TEMPSTRINGLENGTH];
    unsigned int globalWinNum;

DEBUG_FUNC1(DEBUGLEVEL);

    [super initFrame:frameRect];
    number = winNum;
    windowNum = windowNumber++;
    flushMode = NONFLUSHMODE;
    flushTE = (DPSTimedEntry)0;
    cache = [[Window allocFromZone:[self zone]] initContent:&bounds style:NX_PLAINSTYLE backing:NX_RETAINED buttonMask:0 defer:NO];
    imageRep = [[NXCachedImageRep allocFromZone:[self zone]] initFromWindow:cache rect:&bounds];
    theImage = [[NXImage allocFromZone:[self zone]] initSize:&(bounds.size)];
    [theImage setUnique:YES];
    [theImage useRepresentation:imageRep];
    [theImage setScalable:YES];
    [ScrollView getFrameSize:&size3 forContentSize:&(bounds.size) horizScroller:YES vertScroller:YES borderType:NX_NOBORDER];
    NXSetRect(&contentRect,0.0,0.0,size3.width,size3.height);
    [Window getFrameRect:frameRect forContentRect:&contentRect style:NX_RESIZEBARSTYLE];
    maxWindowSize.width = frameRect->size.width;
    maxWindowSize.height = frameRect->size.height;
    NXConvertWinNumToGlobal([cache windowNum], &globalWinNum);
    [[NXApp protocolObj] sendGraphicsWindow:globalWinNum];

    [[NXApp prefAgent] getGraphicsSize:&size1];
    [[NXApp prefAgent] getGraphicsTolerance:&size2];
    size1.width = (((size1.width+size2.width)<bounds.size.width)?size1.width:bounds.size.width);
    size1.height = (((size1.height+size2.height)<bounds.size.height)?size1.height:bounds.size.height);

    [ScrollView getFrameSize:&size3 forContentSize:&size1 horizScroller:YES vertScroller:YES borderType:NX_NOBORDER];
    [ScrollView getFrameSize:&size5 forContentSize:&size4 horizScroller:YES vertScroller:YES borderType:NX_NOBORDER];
    size3.width = MAX(size3.width, size5.width);
    size3.height = MAX(size3.height, size5.height);
    NXSetRect(frameRect,0.0,0.0,size3.width,size3.height);
    scrollView = [[ScrollView allocFromZone:[self zone]] initFrame:frameRect];
    [scrollView setBorderType:NX_NOBORDER];
    [scrollView setHorizScrollerRequired:YES];
    [scrollView setVertScrollerRequired:YES];
    [scrollView setDocView:self];

    theWindow = [[Panel allocFromZone:[self zone]] initContent:frameRect style:NX_RESIZEBARSTYLE backing:NX_BUFFERED buttonMask:NX_RESIZEBUTTONMASK|NX_MINIATURIZEBUTTONMASK defer:NO];
    [theWindow setFreeWhenClosed:YES];
    [theWindow setHideOnDeactivate:NO];
    [theWindow setMiniwindowIcon:MINIWINDOWICON];
    [theWindow setDelegate:self];
    [theWindow moveTopLeftTo:(WINDOWRIGHTBOUND-frameRect->size.width) :(WINDOWTOPBOUND-((windowNum*WINDOWOFFSET)%WINDOWROLLBOUND))];
    sprintf(buffer, GENERICTITLE, windowNum);
    [theWindow setTitle:buffer];
    [theWindow setContentView:scrollView];

    [theWindow display];
    [NXApp addWindowsItem:theWindow title:buffer filename:NO];
    [theWindow orderWindow:NX_BELOW relativeTo:[[NXApp mainWindow] windowNum]];
    return self;
}

- drawSelf:(NXRect *)r :(int)rectCount
{
DEBUG_FUNC1(DEBUGLEVEL);
    [theImage composite:NX_COPY fromRect:r toPoint:&(r->origin)];
    return self;
}

- free
{
DEBUG_FUNC1(DEBUGLEVEL);
    [theImage free];
    [cache free];
    return [super free];
}

- setFlushMode:(unsigned)mode
{
    switch (mode)
      {
        case AUTOFLUSHMODE: flushTE = DPSAddTimedEntry(0.1, (DPSTimedEntryProc)flushTEHandler, self, NX_MODALRESPTHRESHOLD-1);
                            flushMode = mode; break;
	case NONFLUSHMODE: if (flushTE) DPSRemoveTimedEntry(flushTE);
	                   flushTE = (DPSTimedEntry)0; flushMode = mode;
      }
    return [self display];
}

@end

@implementation GraphicsView (Delegate)

- windowWillResize:sender toSize:(NXSize *)aSize
{
DEBUG_FUNC1(DEBUGLEVEL);
    if (aSize->width > maxWindowSize.width)
      aSize->width = maxWindowSize.width;
    if (aSize->width < minWindowSize.width)
      aSize->width = minWindowSize.width;
    if (aSize->height > maxWindowSize.height)
      aSize->height = maxWindowSize.height;
    if (aSize->height < minWindowSize.height)
      aSize->height = minWindowSize.height;
    return self;
}   

@end

static void flushTEHandler(DPSTimedEntry te, double time, id self)
{
    [self display];
}

@interface Window (FrameView)
- _setCloseEnabled:(BOOL)aBoolean andDisplay:(BOOL)anotherBool;
@end

@implementation Window (GraphicsExt)

- setCloseEnabled
{
DEBUG_FUNC1(DEBUGLEVEL);
    [_borderView _setCloseEnabled:YES andDisplay:YES];
    return self;
}

@end
